/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.zul;

import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.type.FieldVo;
import cn.easyplatform.web.ext.*;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.ext.Disable;
import org.zkoss.zul.*;

import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class Surveybox extends Vlayout implements ZkExt, Reloadable, Disable, Assignable {

    /**
     * 查询语句,结果column个数可以有1-3个,当1个的时候value和label共用，2个时分别表示value和label，3个时最后一个是图片
     */
    private String _query;

    /**
     * 数据连接的资源id
     */
    private String _dbId;

    /**
     * 过滤表达式
     */
    private String _filter;

    /**
     * 分组查询
     */
    private String _groupQuery;

    /**
     * 具体条目查询
     */
    private String _detailQuery;

    /**
     * 选择题中子题目间隔
     */
    private String _itemSpacing = "10px";

    /**
     * 显示得分类型(0-不表示;1-显示;2-评分)
     */
    private int _scoreType;

    /**
     *
     */
    private boolean _disabled;
    /**
     * 是否必需重新加载
     */
    private boolean _force;

    //是否显示答案
    private boolean _showAnswer;

    //多选题分隔符
    public String _splitChar = ",";

    //多选项使用模式
    private boolean _strictMode = true;

    public String getSplitChar() {
        return _splitChar;
    }

    public void setSplitChar(String splitChar) {
        this._splitChar = splitChar;
    }

    public boolean isStrictMode() {
        return _strictMode;
    }

    public void setStrictMode(boolean strictMode) {
        this._strictMode = strictMode;
    }

    public boolean isShowAnswer() {
        return _showAnswer;
    }

    public void setShowAnswer(boolean showAnswer) {
        this._showAnswer = showAnswer;
    }

    @Override
    public boolean isForce() {
        return _force;
    }

    public void setForce(boolean force) {
        this._force = force;
    }

    public String getItemSpacing() {
        return _itemSpacing;
    }

    public void setItemSpacing(String itemSpacing) {
        this._itemSpacing = itemSpacing;
    }

    public int getScoreType() {
        return _scoreType;
    }

    public void setScoreType(int scoreType) {
        this._scoreType = scoreType;
    }

    public String getDetailQuery() {
        return _detailQuery;
    }

    public void setDetailQuery(String detailQuery) {
        this._detailQuery = detailQuery;
    }

    public String getQuery() {
        return _query;
    }

    public void setQuery(String query) {
        this._query = query;
    }

    public String getDbId() {
        return _dbId;
    }

    public void setDbId(String dbId) {
        this._dbId = dbId;
    }

    public String getFilter() {
        return _filter;
    }

    public void setFilter(String filter) {
        this._filter = filter;
    }

    public String getGroupQuery() {
        return _groupQuery;
    }

    public void setGroupQuery(String groupQuery) {
        this._groupQuery = groupQuery;
    }

    @Override
    public void setValue(Object value) {
        Assignable ext = (Assignable) getAttribute("$proxy");
        if (ext != null)
            ext.setValue(value);
    }

    @Override
    public Object getValue() {
        Assignable ext = (Assignable) getAttribute("$proxy");
        if (ext != null)
            return ext.getValue();
        return null;
    }

    @Override
    public boolean isDisabled() {
        return _disabled;
    }

    @Override
    public void setDisabled(boolean disabled) {
        this._disabled = disabled;
        Iterator<Component> itr = queryAll("div").iterator();
        while (itr.hasNext()) {
            Component div = itr.next();
            Node node = (Node) div.getAttribute("value");
            if (node != null) {
                div = div.getNextSibling();
                FieldVo[] fvs = node.getData();
                int type = Nums.toInt(fvs[0].getValue(), 1);
                if (type == 1) {
                    Radiogroup rg = (Radiogroup) div.query("radiogroup");
                    for (Radio radio : rg.getItems())
                        radio.setDisabled(disabled);
                } else if (type == 2) {
                    Iterator<Component> chkItr = div.queryAll("checkbox").iterator();
                    while (chkItr.hasNext()) {
                        Checkbox cbx = (Checkbox) chkItr.next();
                        cbx.setDisabled(disabled);
                    }
                } else if (type == 3) {
                    Textbox tbx = (Textbox) div.query("textbox");
                    tbx.setReadonly(disabled);
                }
            }
        }
    }

    @Override
    public void reload() {
        Widget ext = (Widget) getAttribute("$proxy");
        ext.reload(this);
    }

    public Object getData(String name) {
        Iterator<Component> itr = queryAll("div").iterator();
        List<Object> data = new ArrayList<>();
        while (itr.hasNext()) {
            Component div = itr.next();
            Node node = (Node) div.getAttribute("value");
            if (node != null) {
                FieldVo[] fvs = node.getData();
                for (FieldVo fv : fvs) {
                    if (name.equalsIgnoreCase(fv.getName())) {
                        data.add(fv.getValue());
                        break;
                    }
                }
            }
        }
        Object[] result = new Object[data.size()];
        data.toArray(result);
        return result;
    }

    public Object getData() {
        Iterator<Component> itr = queryAll("div").iterator();
        List<Object> data = new ArrayList<>();
        while (itr.hasNext()) {
            Component div = itr.next();
            Node node = (Node) div.getAttribute("value");
            if (node != null) {
                FieldVo[] fvs = node.getData();
                Object[] vals = new Object[fvs.length];
                for (int i = 0; i < fvs.length; i++)
                    vals[i] = fvs[i].getValue();
                data.add(vals);
            }
        }
        Object[] result = new Object[data.size()];
        data.toArray(result);
        return result;
    }

    public double getTotalScore() {
        if (_scoreType > 0) {
            Iterator<Component> itr = queryAll("div").iterator();
            double total = 0d;
            while (itr.hasNext()) {
                Component div = itr.next();
                Node node = (Node) div.getAttribute("value");
                if (node != null) {
                    FieldVo[] fvs = node.getData();
                    int type = Nums.toInt(fvs[0].getValue(), 1);
                    if (type == 1) {//单选题
                        Radiogroup rg = (Radiogroup) div.getNextSibling().query("radiogroup");
                        if (rg.getSelectedIndex() >= 0) {
                            Node child = rg.getSelectedItem().getValue();
                            if (child.getId().equals(fvs[4].getValue())) {
                                total += Nums.toDouble(fvs[3].getValue(), 0d);
                            }
                        }
                    } else if (type == 2 && _strictMode) {
                        Iterator<Component> irg = div.getNextSibling().queryAll("checkbox").iterator();
                        List<String> answers;
                        if (Strings.isBlank(this._splitChar)) {
                            char[] ars = fvs[4].getValue().toString().toCharArray();
                            answers = new ArrayList<>(ars.length);
                            for (int i = 0; i < ars.length; i++)
                                answers.add(String.valueOf(ars[i]));
                        } else
                            answers = new ArrayList<>(Arrays.asList(fvs[4].getValue().toString().split(this._splitChar)));
                        while (irg.hasNext()) {
                            Checkbox cbx = (Checkbox) irg.next();
                            if (cbx.isChecked()) {
                                Node child = cbx.getValue();
                                answers.remove(child.getId());
                            }
                        }
                        if (answers.isEmpty())
                            total += Nums.toDouble(fvs[3].getValue(), 0d);
                    } else {//多选或做题
                        Doublebox db = (Doublebox) div.query("doublebox");
                        total += db.getValue();
                    }
                }
            }
            return total;
        }
        return 0d;
    }

    public Map<Object, Double> getScores() {
        if (_scoreType > 0) {
            Iterator<Component> itr = queryAll("div").iterator();
            Map<Object, Double> data = new HashMap<>();
            while (itr.hasNext()) {
                Component div = itr.next();
                Node node = (Node) div.getAttribute("value");
                if (node != null) {
                    FieldVo[] fvs = node.getData();
                    int type = Nums.toInt(fvs[0].getValue(), 1);
                    if (type == 1) {//单选题
                        Label db = (Label) div.getLastChild().query("label");
                        Radiogroup rg = (Radiogroup) div.getNextSibling().query("radiogroup");
                        if (rg.getSelectedIndex() >= 0) {
                            Node child = rg.getSelectedItem().getValue();
                            if (child.getId().equals(fvs[4].getValue())) {
                                double val = Nums.toDouble(fvs[3].getValue(), 0d);
                                data.put(fvs[1].getValue(), val);
                                db.setValue(val + "");
                            } else {
                                data.put(fvs[1].getValue(), 0d);
                                db.setValue("0");
                            }
                        } else {
                            data.put(fvs[1].getValue(), 0d);
                        }
                    } else if (type == 2 && _strictMode) {
                        Label db = (Label) div.getLastChild().query("label");
                        Iterator<Component> irg = div.getNextSibling().queryAll("checkbox").iterator();
                        List<String> answers;
                        if (Strings.isBlank(this._splitChar)) {
                            char[] ars = fvs[4].getValue().toString().toCharArray();
                            answers = new ArrayList<>(ars.length);
                            for (int i = 0; i < ars.length; i++)
                                answers.add(String.valueOf(ars[i]));
                        } else
                            answers = new ArrayList<>(Arrays.asList(fvs[4].getValue().toString().split(this._splitChar)));
                        while (irg.hasNext()) {
                            Checkbox cbx = (Checkbox) irg.next();
                            if (cbx.isChecked()) {
                                Node child = cbx.getValue();
                                answers.remove(child.getId());
                            }
                        }
                        if (answers.isEmpty()) {
                            double val = Nums.toDouble(fvs[3].getValue(), 0d);
                            db.setValue(val + "");
                            data.put(fvs[1].getValue(), val);
                        } else {
                            data.put(fvs[1].getValue(), 0d);
                            db.setValue("0");
                        }
                    } else {//多选或做题
                        Doublebox db = (Doublebox) div.query("doublebox");
                        data.put(fvs[1].getValue(), db.getValue());
                    }
                }
            }
            return data;
        }
        return null;
    }
}
